package com.woshengqile.dao;

import java.io.IOException;

import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.Db;
import com.woshengqile.CommonAttributes;
import com.woshengqile.model.Sn;
import com.woshengqile.util.Assert;
import com.woshengqile.util.FreeMarkerUtils;

import freemarker.template.TemplateException;

/**
 * Dao - 序列号
 * 
 */
public class SnDao extends BaseDao<Sn> {
	
	/**
	 * 构造方法
	 */
	public SnDao() {
		super(Sn.class);
	}
	
	Prop prop = PropKit.use(CommonAttributes.JFINALSHOP_PROPERTIES_PATH);

	/**
	 * 商品编号生成器
	 */
	private String productPrefix = prop.get("sn.product.prefix");
	private int productMaxLo = prop.getInt("sn.product.maxLo");
	private HiloOptimizer productHiloOptimizer = new HiloOptimizer(Sn.Type.product, productPrefix, productMaxLo);

	/**
	 * 订单编号生成器
	 */
	private String orderPrefix = prop.get("sn.order.prefix");
	private int orderMaxLo = prop.getInt("sn.order.maxLo");
	private HiloOptimizer orderHiloOptimizer = new HiloOptimizer(Sn.Type.order, orderPrefix, orderMaxLo);

	/**
	 * 订单支付编号生成器
	 */
	private String orderPaymentPrefix = prop.get("sn.orderPayment.prefix");
	private int orderPaymentMaxLo = prop.getInt("sn.orderPayment.maxLo");
	private HiloOptimizer orderPaymentHiloOptimizer = new HiloOptimizer(Sn.Type.orderPayment, orderPaymentPrefix, orderPaymentMaxLo);

	/**
	 * 订单退款编号生成器
	 */
	private String orderRefundsPrefix = prop.get("sn.orderRefunds.prefix");
	private int orderRefundsMaxLo = prop.getInt("sn.orderRefunds.maxLo");
	private HiloOptimizer orderRefundsHiloOptimizer = new HiloOptimizer(Sn.Type.orderRefunds, orderRefundsPrefix, orderRefundsMaxLo);

	/**
	 * 订单发货编号生成器
	 */
	private String orderShippingPrefix = prop.get("sn.orderShipping.prefix");
	private int orderShippingMaxLo = prop.getInt("sn.orderShipping.maxLo");
	private HiloOptimizer orderShippingHiloOptimizer = new HiloOptimizer(Sn.Type.orderShipping, orderShippingPrefix, orderShippingMaxLo);

	/**
	 * 订单退货编号生成器
	 */
	private String orderReturnsPrefix = prop.get("sn.orderReturns.prefix");
	private int orderReturnsMaxLo = prop.getInt("sn.orderReturns.maxLo");
	private HiloOptimizer orderReturnsHiloOptimizer = new HiloOptimizer(Sn.Type.orderReturns, orderReturnsPrefix, orderReturnsMaxLo);

	/**
	 * 支付事务编号生成器
	 */
	private String paymentTransactionPrefix = prop.get("sn.paymentTransaction.prefix");
	private int paymentTransactionMaxLo = prop.getInt("sn.paymentTransaction.maxLo");
	private HiloOptimizer paymentTransactionHiloOptimizer = new HiloOptimizer(Sn.Type.paymentTransaction, paymentTransactionPrefix, paymentTransactionMaxLo);

	/**
	 * 平台服务编号生成器
	 */
	private String platformServicePrefix = prop.get("sn.platformService.prefix");
	private int platformServiceMaxLo = prop.getInt("sn.platformService.maxLo");
	private HiloOptimizer platformServiceHiloOptimizer = new HiloOptimizer(Sn.Type.platformService, platformServicePrefix, platformServiceMaxLo);
	
	/**
	 * 盘点入库单编号生成器
	 */
	private String stockPrefix = prop.get("sn.stock.prefix");
	private int stockMaxLo = prop.getInt("sn.stock.maxLo");
	private HiloOptimizer stockHiloOptimizer = new HiloOptimizer(Sn.Type.stock, stockPrefix, stockMaxLo);
	
	
	/**
	 * 生成序列号
	 * 
	 * @param type
	 *            类型
	 * @return 序列号
	 */
	public String generate(Sn.Type type) {
		Assert.notNull(type);

		switch (type) {
		case product:
			return productHiloOptimizer.generate();
		case order:
			return orderHiloOptimizer.generate();
		case orderPayment:
			return orderPaymentHiloOptimizer.generate();
		case orderRefunds:
			return orderRefundsHiloOptimizer.generate();
		case orderShipping:
			return orderShippingHiloOptimizer.generate();
		case orderReturns:
			return orderReturnsHiloOptimizer.generate();
		case paymentTransaction:
			return paymentTransactionHiloOptimizer.generate();
		case platformService:
			return platformServiceHiloOptimizer.generate();
		case stock:
			return stockHiloOptimizer.generate();
		default:
			break;
		}
		return null;
	}
	
	/**
	 * 获取末值
	 * 
	 * @param type
	 *            类型
	 * @return 末值
	 */
	private long getLastValue(Sn.Type type) {
		String sql = "SELECT * FROM sn WHERE type = ?";
		Sn sn = modelManager.findFirst(sql, type.ordinal());
		long lastValue = sn.getLastValue();
		String updateSql = "UPDATE sn SET last_value = ? WHERE type = ?";
		int result = Db.update(updateSql, lastValue + 1, type.ordinal());
		return 0 < result ? lastValue : getLastValue(type);
	}

	/**
	 * 高低位算法生成器
	 */
	private class HiloOptimizer {

		/**
		 * 类型
		 */
		private Sn.Type type;

		/**
		 * 前缀
		 */
		private String prefix;

		/**
		 * 最大低位值
		 */
		private int maxLo;

		/**
		 * 低位值
		 */
		private int lo;

		/**
		 * 高位值
		 */
		private long hi;

		/**
		 * 末值
		 */
		private long lastValue;

		/**
		 * 构造方法
		 * 
		 * @param type
		 *            类型
		 * @param prefix
		 *            前缀
		 * @param maxLo
		 *            最大低位值
		 */
		HiloOptimizer(Sn.Type type, String prefix, int maxLo) {
			this.type = type;
			this.prefix = prefix != null ? prefix.replace("{", "${") : "";
			this.maxLo = maxLo;
			this.lo = maxLo + 1;
		}

		/**
		 * 生成序列号
		 * 
		 * @return 序列号
		 */
		public synchronized String generate() {
			if (lo > maxLo) {
				lastValue = getLastValue(type);
				lo = lastValue == 0 ? 1 : 0;
				hi = lastValue * (maxLo + 1);
			}
			try {
				return FreeMarkerUtils.process(prefix) + (hi + lo++);
			} catch (IOException e) {
				throw new RuntimeException(e.getMessage(), e);
			} catch (TemplateException e) {
				throw new RuntimeException(e.getMessage(), e);
			}
		}
	}

}